﻿#region Apache 2.0 License header

//   Copyright 2012 Lesley van Zijl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License. 

#endregion

using System;
using System.Reflection;
using System.Reflection.Emit;
using FavourObjects;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Tests.Helpers;

namespace Tests
{
    [TestClass]
    public class SpecialMethodArgsTests
    {
        [TestMethod]
        public void Out_Arg_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            MethodInfo methodInfo;
            favourObject.OutArgMethod(out methodInfo);

            Assert.IsNotNull(methodInfo);
        }

        [TestMethod]
        public void Ref_Arg_ReferenceType_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            MethodInfo methodInfo = new DynamicMethod("F", null, Type.EmptyTypes);
            favourObject.RefArgMethod(ref methodInfo);

            Assert.IsNull(methodInfo);
        }

        [TestMethod]
        public void Ref_Arg_Array_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            var methodInfos = new MethodInfo[] {new DynamicMethod("F", null, Type.EmptyTypes)};
            favourObject.RefArrayArgMethod(ref methodInfos);

            Assert.IsNull(methodInfos[0]);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_Int32_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            int input = 5;
            favourObject.RefArgValueTypeMethodInt32(ref input);

            Assert.AreEqual(16, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_UInt32_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            uint input = 5;
            favourObject.RefArgValueTypeMethodUInt32(ref input);

            Assert.AreEqual((UInt32) 16, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_Int16_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            Int16 input = 5;
            favourObject.RefArgValueTypeMethodInt16(ref input);

            Assert.AreEqual(16, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_UInt16_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            UInt16 input = 5;
            favourObject.RefArgValueTypeMethodUInt16(ref input);

            Assert.AreEqual((UInt16) 16, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_Char_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            Char input = '5';
            favourObject.RefArgValueTypeMethodChar(ref input);

            Assert.AreEqual('3', input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_Int64_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            Int64 input = 5;
            favourObject.RefArgValueTypeMethodInt64(ref input);

            Assert.AreEqual(16, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_UInt64_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            UInt64 input = 5;
            favourObject.RefArgValueTypeMethodUInt64(ref input);

            Assert.AreEqual((UInt64) 16, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_Byte_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            Byte input = 5;
            favourObject.RefArgValueTypeMethodByte(ref input);

            Assert.AreEqual(16, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_SByte_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            SByte input = 5;
            favourObject.RefArgValueTypeMethodSByte(ref input);

            Assert.AreEqual(16, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_Double_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            Double input = 5.0d;
            favourObject.RefArgValueTypeMethodDouble(ref input);

            Assert.AreEqual(16.0d, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_Single_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            Single input = 5.0f;
            favourObject.RefArgValueTypeMethodSingle(ref input);

            Assert.AreEqual(16.0f, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_Boolean_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            Boolean input = false;
            favourObject.RefArgValueTypeMethodBoolean(ref input);

            Assert.AreEqual(true, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_Decimal_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            Decimal input = 45;
            favourObject.RefArgValueTypeMethodDecimal(ref input);

            Assert.AreEqual(67, input);
        }

        [TestMethod]
        public void Ref_Arg_ValueType_Guid_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            Guid input = Guid.NewGuid();
            favourObject.RefArgValueTypeMethodGuid(ref input);

            Assert.AreEqual(Guid.Empty, input);
        }

        [TestMethod]
        public void ParamsValue_Arg_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            favourObject.ParamsValueArgMethod(1, 2, 3, 4, 5);
        }

        [TestMethod]
        public void ParamsReference_Arg_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            MethodInfo mi1 = new DynamicMethod("F1", null, Type.EmptyTypes);
            MethodInfo mi2 = new DynamicMethod("F2", null, Type.EmptyTypes);
            MethodInfo mi3 = new DynamicMethod("F3", null, Type.EmptyTypes);

            favourObject.ParamsReferenceArgMethod(mi1, mi2, mi3);
        }

        [TestMethod]
        public void OutAndRef_Arg_Test()
        {
            var favourObject = FavourObject.Create<ISpecialMethodArgs>(new TargetTestClass());

            MethodInfo miOut;
            MethodInfo miRef = new DynamicMethod("F", null, Type.EmptyTypes);

            favourObject.OutAndRefArgMethod(ref miRef, out miOut);

            Assert.IsNotNull(miOut);
        }

        #region Nested type: ISpecialMethodArgs

        public interface ISpecialMethodArgs
        {
            void OutArgMethod(out MethodInfo methodInfo);

            void RefArgMethod(ref MethodInfo methodInfo);
            void RefArrayArgMethod(ref MethodInfo[] methodInfo);

            void ParamsValueArgMethod(params int[] p);

            void ParamsReferenceArgMethod(params MethodInfo[] methodInfos);

            void OutAndRefArgMethod(ref MethodInfo miRef, out MethodInfo miOut);

            void RefArgValueTypeMethodInt32(ref Int32 number);
            void RefArgValueTypeMethodUInt32(ref UInt32 number);
            void RefArgValueTypeMethodInt16(ref Int16 number);
            void RefArgValueTypeMethodUInt16(ref UInt16 number);
            void RefArgValueTypeMethodInt64(ref Int64 number);
            void RefArgValueTypeMethodUInt64(ref UInt64 number);
            void RefArgValueTypeMethodChar(ref Char c);
            void RefArgValueTypeMethodByte(ref Byte number);
            void RefArgValueTypeMethodSByte(ref SByte number);
            void RefArgValueTypeMethodDouble(ref Double number);
            void RefArgValueTypeMethodSingle(ref Single number);
            void RefArgValueTypeMethodGuid(ref Guid guid);
            void RefArgValueTypeMethodDecimal(ref Decimal d);
            void RefArgValueTypeMethodBoolean(ref Boolean b);
        }

        #endregion
    }
}